
package com.x52im.rbchat.logic.contact.viewmodel;

import android.util.Log;

import com.eva.android.ArrayListObservable;
import com.x52im.rbchat.MyApplication;
import com.x52im.rainbowchat.http.logic.dto.RosterElementEntity;
import com.x52im.rbchat.logic.chat_friend.utils.ObserverFactory;
import com.x52im.rbchat.logic.contact.model.FriendItemValue;

import net.x52im.mobileimsdk.android.utils.MBThreadPoolExecutor;

import java.util.List;
import java.util.Observer;
import java.util.concurrent.atomic.AtomicInteger;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * 用于新版好友列表的ViewModel实现类。
 *
 * @author JackJiang
 * @since 8.0
 */
public class FriendsViewModel extends ViewModel {

    private final static String TAG = FriendsViewModel.class.getSimpleName();

    /** 好友列表数据载入LiveData对象（当本类从IMClientManger的全局好友数据缓存中载入完成时，通过本对象通知ui更新） */
    private MutableLiveData<List<FriendItemValue>> friendsDataReloadLiveData = null;
    /** 好友列表数据变动LiveData对象（当IMClientManger中的全局好友数据缓存发生改变时(可能是新增、删除、信息修改等)，通过本对象通知ui更新） */
    private MutableLiveData<Object> friendsDataChangedLiveData = null;

    /** 添加至IMClientManger中的全局好友数据缓存的好友在线状态观察者 */
    private Observer friendsLiveStatusChangeObs = null;
    /** 添加至IMClientManger中的全局好友数据缓存的变动观察者(变动可能是新增、删除、信息修改等) */
    private Observer friendsDataChangedObserver = null;

    /** 这是一个支持多线程原子读的标识量（比布尔量使用更灵活），当载入好友数据时+1、载入完成时-1，目的是防止重复加载 */
    private final AtomicInteger loadingFriendsCount = new AtomicInteger(0);

    public FriendsViewModel() {
        this.initLiveData();
    }

    /**
     * 本ViewModel类被回收时将要做的处理。
     */
    @Override
    protected void onCleared() {
        super.onCleared();

        Log.i(TAG, "@@@@【FriendsViewModel】onCleared被调用了！");

        // 从IMClientManger中的全局好友数据缓存模型上清除好友在线状态观察者
        RosterElementEntity.removeLiveStatusChangeObs(this.friendsLiveStatusChangeObs);
        // 从IMClientManger中的全局好友数据缓存模型上清除数据变动观察者
        if(this.friendsDataChangedObserver != null) {
            MyApplication.getInstance2()
                    .getIMClientManager()
                    .getFriendsListProvider()
                    .getRosterData(null, false)
                    .removeObserver(this.friendsDataChangedObserver);
        }
    }

    /**
     * 各liveData对象初始化。
     */
    private void initLiveData(){

        Log.i(TAG, "@@@@【FriendsViewModel】initLiveData被调用了！");

        if (this.friendsDataReloadLiveData == null) {
            this.friendsDataReloadLiveData = new MutableLiveData<>();
        }
        if(this.friendsDataChangedLiveData == null){
            this.friendsDataChangedLiveData = new MutableLiveData<>();
        }

        // 设置IMClientManger中的全局好友数据缓存的好友在线状态观察者
        if(this.friendsLiveStatusChangeObs == null){
            this.friendsLiveStatusChangeObs = new ObserverFactory.FriendLiveStatusChangeObs(){
                @Override
                protected void fireOnline(String nickName, String friendUid) {
                    Log.i(TAG, "@@@@【FriendsViewModel】"+nickName+"上线了->，马上通过postValue通知ui！");
                    friendsDataChangedLiveData.postValue(friendUid);
                }

                @Override
                protected void fireOffline(String nickName, String friendUid) {
                    Log.i(TAG, "@@@@【FriendsViewModel】"+nickName+"下线了<-，马上通过postValue通知ui！");
                    friendsDataChangedLiveData.postValue(friendUid);
                }
            };

            // 设置好友上下线状态观察者
            RosterElementEntity.addLiveStatusChangeObs(this.friendsLiveStatusChangeObs);

            Log.i(TAG, "@@@@【FriendsViewModel】initLiveData中.setLiveStatusChangeObs(this.friendsLiveStatusChangeObs)！");
        }

        // 设置IMClientManger中的全局好友数据缓存的变动观察者(变动可能是新增、删除、信息修改等)
        if(this.friendsDataChangedObserver == null){
            this.friendsDataChangedObserver = (observable, o) -> {
                // 从观察者中读取变动的数据内容
                ArrayListObservable.UpdateDataToObserver<Object> udto = null;
                if (o != null){
                    udto = (ArrayListObservable.UpdateDataToObserver<Object>)o;
                    // 当有新好友加入（添加好友完成）时，就通知本类重新加载整个列表（加载的过程中将会
                    // 重新计算索引字母、排序等，不然无法实现新好友在列表中的位置）
                    if(udto.getUpdateType() == ArrayListObservable.UpdateTypeToObserver.add){
                        Log.i(TAG, "@@@@【FriendsViewModel】全局数据模型中已add了一条数据，马上reloadFriendsData(..)！");
                        // 重新加载列表数据（用于ui显示）
                        reloadFriendsData();
                        return;
                    }

                    // 【补充：为何好友被删除时，此处不需要重新加载？】
                    // 原因是：删除必然是在本类的宿主（即FriendListFragment类中）界面之外去由用户主动去删除（比如在
                    //        好友信息界面中），当用户删除完成回到本类的宿主（即FriendListFragment类中）时，
                    //        FriendListFragmen会通过onResume回调即时重新加载数据，也就不需要在这里重复处理了。
                }

                Log.i(TAG, "@@@@【FriendsViewModel】全局数据模型中数据已发生改动，马上通过postValue通知ui层！");
                // 普通的数据变动（可能是信息修改等）更新通知ui刷新显示即可
                friendsDataChangedLiveData.postValue(udto);
            };

            // 设置观察者
            MyApplication.getInstance2()
                    .getIMClientManager()
                    .getFriendsListProvider()
                    .getRosterData(null, false)
                    .addObserver(this.friendsDataChangedObserver);

            Log.i(TAG, "@@@@【FriendsViewModel】initLiveData中..getRosterData().addObserver(this.listDatasObserver)！");
        }
    }

    public MutableLiveData<List<FriendItemValue>> getFriendsDataReloadLiveData(){
        return this.friendsDataReloadLiveData;
    }

    public MutableLiveData<Object> getFriendsDataChangedLiveData(){
        return this.friendsDataChangedLiveData;
    }

    public void reloadFriendsData() {

        Log.i(TAG, "@@@@【FriendsViewModel】reloadFriendsData正在被调用。。。。");

        // 加载指示标识（用于防止多线程重复加载）
        int count = loadingFriendsCount.get();
        if (count > 0) {
            return;
        }

        // 加载开始时指示标识+1
        loadingFriendsCount.incrementAndGet();

        // 数据处理逻辑在后台进行，提升ui体验
        MBThreadPoolExecutor.runInBackground(() -> {
            long t = System.currentTimeMillis();
            // 加载完成时指示标识-1
            loadingFriendsCount.decrementAndGet();

            // 读取原始好友信息数据
            ArrayListObservable<RosterElementEntity> rosterData = MyApplication.getInstance2().getIMClientManager()
                    .getFriendsListProvider().getRosterData(null, false);
            List<RosterElementEntity> userInfos = rosterData.getDataList();

            // 将处理好的用于好友列表ui显示的数据通知给观察者（以备ui刷新显示）
            if (friendsDataReloadLiveData != null) {
                friendsDataReloadLiveData.postValue(FriendItemValue.fromUserInfos(userInfos));
                Log.i(TAG, "@@@@【FriendsViewModel】reloadContact完成，耗时："+(System.currentTimeMillis()-t)+"ms");
            }
        });
    }
}
